#ifndef CRASH_DUMP_MINGW_H
#define CRASH_DUMP_MINGW_H


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <backtrace.h>  // libbacktrace 核心头文件
#include <windows.h>    // Windows 平台辅助（获取程序路径）

namespace CRASHDMP_CPP {
// ------------------------------
// 全局变量声明（静态化，避免多文件包含冲突）
// ------------------------------
// libbacktrace 状态句柄（初始化后复用）
static struct backtrace_state * g_backtrace_state = NULL;
// 崩溃日志文件指针（仅在崩溃时使用）
static FILE* g_crash_log = NULL;
static const char* g_log_prefix = ".";
// ------------------------------
// 前置声明（避免编译警告）
// ------------------------------
static void backtrace_error_cb(void* data, const char* msg, int errnum);
static int backtrace_frame_cb(void* data, uintptr_t pc, const char* filename, int line, const char* function);
void crash_handler(int sig);
void init_crash_handler_once(void);
void init_crash_handler(const char* log_prefix);  // 扩展：自定义日志路径

// ------------------------------
// 扩展接口：自定义崩溃日志保存路径（可选调用）
// 示例：init_crash_handler_with_path("D:/crash_logs");
// ------------------------------
void init_crash_handler(const char* log_prefix) {
	if (log_prefix)
		g_log_prefix = log_prefix;
	init_crash_handler_once();  // 调用核心初始化
}

// ------------------------------
// 1. libbacktrace 错误回调函数（符号解析失败时触发）
// ------------------------------
static void backtrace_error_cb(void* data, const char* msg, int errnum) {
	(void)data;  // 忽略未使用参数，避免编译警告
	// 输出错误信息到日志（日志打开失败则输出到 stderr）
	const char* err_msg = (errnum != 0) ? strerror(errnum) : "NORMAL";
	fprintf_s(g_crash_log ?: stderr, "BACKTRACE ERROR：%s（CODE：%d，DETAIL：%s）\n", msg, errnum, err_msg);
}

// ------------------------------
// 2. libbacktrace 栈帧回调函数（每个栈帧触发一次）
// ------------------------------
static int backtrace_frame_cb(void* data, uintptr_t pc, const char* filename, int line, const char* function) {
	(void)data;  // 忽略未使用参数
	static int stack_depth = 0;  // 栈深度计数（仅初始化一次）

	// 格式化输出栈帧信息（兼容 C/C++，避免格式警告）
	fprintf_s(g_crash_log, "[%d] PC: 0x%lx | FUNC: %s | POS: %s:%d\n",
			stack_depth++,
			(unsigned long)pc,
			function ? function : "unknown",  // 空指针安全访问
			filename ? filename : "unknown",
			line > 0 ? line : 0);

	return 0;  // 返回 0 继续回溯下一个栈帧
}

// ------------------------------
// 3. 崩溃信号处理函数（捕获常见崩溃信号）
// ------------------------------
void crash_handler(int sig) {
	// 信号名称映射表（扩展更多常见信号，兼容 MinGW64 环境）
	const char* sig_name = NULL;
	switch (sig) {
	case SIGSEGV: sig_name = "SIGSEGV (段错误/访问非法地址)"; break;
	case SIGABRT: sig_name = "SIGABRT (断言失败/主动终止)";   break;
	case SIGILL:  sig_name = "SIGILL (非法指令)";             break;
	case SIGFPE:  sig_name = "SIGFPE (浮点错误/除零)";        break;
	//case SIGBUS:  sig_name = "SIGBUS (总线错误/地址对齐错误)"; break;
	case SIGINT:  sig_name = "SIGINT (用户中断/Ctrl+C)";      break;
	case SIGTERM: sig_name = "SIGTERM (进程终止信号)";        break;
	//case SIGQUIT: sig_name = "SIGQUIT (退出信号/Ctrl+\\)";    break;
	default:      sig_name = "Unknown Signal";                break;
	};

	// 全局变量：日志保存路径（默认当前目录，可通过扩展接口修改）
	time_t now = time(NULL);
	char log_date[16384] = {0};
	char log_filename[16384] = {0};
	strftime(log_date, sizeof(log_date),
			 ".crash_log_%Y%m%d_%H%M%S.txt", localtime(&now));
	strcpy_s(log_filename,g_log_prefix);
	strcat_s(log_filename,log_date);

	// 打开日志文件（追加模式，若目录不存在则尝试创建）
	g_crash_log = fopen(log_filename, "a");

	// 日志文件仍打开失败，输出到 stderr
	if (!g_crash_log) {
		g_crash_log = stderr;
		fprintf_s(g_crash_log, "Warning, Log file creation Error ( PATH=%s), stderr is activated instead.\n", log_filename);
	} else {
		// 打印日志文件路径到控制台（方便用户查找）
		fprintf_s(stdout, "CrashLog created : %s\n", log_filename);
	}

	// 写入崩溃头部信息（兼容 C/C++ 字符串格式）
	fprintf_s(g_crash_log, "=========================================\n");
	fprintf_s(g_crash_log, "程序崩溃时间：%s", ctime(&now));
	fprintf_s(g_crash_log, "崩溃信号：%d（%s）\n", sig, sig_name);
	fprintf_s(g_crash_log, "堆栈回溯信息（函数名+行号，需编译时加 -g）：\n");

	// 执行栈回溯（skip=1 跳过当前 crash_handler 栈帧）

	/*
extern int backtrace_full (struct backtrace_state *state, int skip,
			   backtrace_full_callback callback,
			   backtrace_error_callback error_callback,
			   void *data);*/
	if (g_backtrace_state != NULL) {
		backtrace_full(g_backtrace_state, 1, backtrace_frame_cb, backtrace_error_cb, (void *)0);
	} else {
		fprintf_s(g_crash_log, "error：libbacktrace is not inited.\n");
	}

	// 收尾：关闭文件+退出程序（避免无限信号循环）
	fprintf_s(g_crash_log, "=========================================\n");
	if (g_crash_log != stderr) {
		fclose(g_crash_log);
	}
	g_crash_log = NULL;  // 重置全局指针
	exit(EXIT_FAILURE);
}
LONG WINAPI crash_exception_handler(PEXCEPTION_POINTERS /*exception_info*/)
{
	crash_handler(0);
	return EXCEPTION_EXECUTE_HANDLER;
}
// ------------------------------
// 4. 核心初始化接口（必须在程序启动时调用）
// 功能：初始化 libbacktrace + 注册崩溃信号处理器
// ------------------------------
void init_crash_handler_once(void) {
	// 初始化 libbacktrace（线程安全模式，自动获取程序路径）
	g_backtrace_state = backtrace_create_state(NULL, 1, backtrace_error_cb, NULL);

	if (!g_backtrace_state) {
		fprintf_s(stderr, "Warning：libbacktrace Initial Failed.\n");
		fprintf_s(stderr, "Possible reason：1. no libbacktrace found. 2. gcc -g not selected. 3. gcc -Wl,-s is enabled in linking time. \n");
		return;
	}

	// 注册常见崩溃信号的处理器（MinGW64 兼容）
	signal(SIGSEGV, crash_handler);  // 段错误
	signal(SIGABRT, crash_handler);  // 断言失败
	signal(SIGILL,  crash_handler);  // 非法指令
	signal(SIGFPE,  crash_handler);  // 浮点错误
	//signal(SIGBUS,  crash_handler);  // 总线错误
	signal(SIGINT,  crash_handler);  // 中断信号（可选，根据需求启用）
	signal(SIGTERM, crash_handler);  // 终止信号（可选）

// Windows 平台额外注册 SEH 异常处理（捕获更多 Windows 特有异常）
	SetUnhandledExceptionFilter(crash_exception_handler);


	fprintf_s(stdout, "CRASGDUMP is online: please enable -g in compile time, and disable -Wl,-s in linking.\n");
}



}


#endif // CRASH_DUMP_MINGW_H
